{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "24ff729c",
   "metadata": {},
   "source": [
    "## Agent和记忆\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "97874632",
   "metadata": {},
   "outputs": [],
   "source": [
    "import os, getpass\n",
    "from dotenv import load_dotenv,find_dotenv\n",
    "\n",
    "load_dotenv(find_dotenv())  # 加载 .env 文件中的环境变量\n",
    "\n",
    "api_key = os.environ.get('OPENAI_API_KEY')\n",
    "base_url = os.environ.get('OPENAI_BASE_URL')\n",
    "\n",
    "def _set_env(var: str):\n",
    "    if not os.environ.get(var):\n",
    "        os.environ[var] = getpass.getpass(f\"{var}: \")\n",
    "\n",
    "_set_env(\"OPENAI_API_KEY\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "cdb516cc",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "LANGCHAIN_API_KEY: ········\n"
     ]
    }
   ],
   "source": [
    "_set_env(\"LANGCHAIN_API_KEY\")\n",
    "os.environ[\"LANGCHAIN_TRACING_V2\"] = \"true\"\n",
    "os.environ[\"LANGCHAIN_PROJECT\"] = \"React-agent-memory\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "45a5d1a5",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain_openai import ChatOpenAI\n",
    "\n",
    "def multiply(a: int, b: int) -> int:\n",
    "    \"\"\"a和b相乘.\n",
    "\n",
    "    Args:\n",
    "        a: first int\n",
    "        b: second int\n",
    "    \"\"\"\n",
    "    return a * b\n",
    "\n",
    "# This will be a tool\n",
    "def add(a: int, b: int) -> int:\n",
    "    \"\"\"a和b相加.\n",
    "\n",
    "    Args:\n",
    "        a: first int\n",
    "        b: second int\n",
    "    \"\"\"\n",
    "    return a + b\n",
    "\n",
    "def divide(a: int, b: int) -> float:\n",
    "    \"\"\"a和b相除.\n",
    "\n",
    "    Args:\n",
    "        a: first int\n",
    "        b: second int\n",
    "    \"\"\"\n",
    "    return a / b\n",
    "\n",
    "tools = [add, multiply, divide]\n",
    "llm = ChatOpenAI(model=\"gpt-4o\")\n",
    "llm_with_tools = llm.bind_tools(tools)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "c372fed8",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langgraph.graph import MessagesState\n",
    "from langchain_core.messages import HumanMessage, SystemMessage\n",
    "\n",
    "# 系统消息\n",
    "sys_msg = SystemMessage(content=\"您是一位乐于助人的助手，负责对一组输入执行算术运算。\")\n",
    "\n",
    "# 节点\n",
    "def assistant(state: MessagesState):\n",
    "   return {\"messages\": [llm_with_tools.invoke([sys_msg] + state[\"messages\"])]}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "043f56d6",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from langgraph.graph import START, StateGraph\n",
    "from langgraph.prebuilt import tools_condition, ToolNode\n",
    "from IPython.display import Image, display\n",
    "\n",
    "# 建立图\n",
    "builder = StateGraph(MessagesState)\n",
    "\n",
    "# 定义节点：这些节点完成相应的工作\n",
    "builder.add_node(\"assistant\", assistant)\n",
    "builder.add_node(\"tools\", ToolNode(tools))\n",
    "\n",
    "# 定义边：这些决定了节点之间如何链接\n",
    "builder.add_edge(START, \"assistant\")\n",
    "builder.add_conditional_edges(\n",
    "    \"assistant\",\n",
    "    tools_condition,\n",
    ")\n",
    "builder.add_edge(\"tools\", \"assistant\")\n",
    "react_graph = builder.compile()\n",
    "\n",
    "display(Image(react_graph.get_graph(xray=True).draw_mermaid_png()))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "a361a89c",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "================================\u001b[1m Human Message \u001b[0m=================================\n",
      "\n",
      "3加4都等于多少？\n",
      "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
      "Tool Calls:\n",
      "  add (call_tEoGniGdaqCkR8f4G5TdGm6J)\n",
      " Call ID: call_tEoGniGdaqCkR8f4G5TdGm6J\n",
      "  Args:\n",
      "    a: 3\n",
      "    b: 4\n",
      "=================================\u001b[1m Tool Message \u001b[0m=================================\n",
      "Name: add\n",
      "\n",
      "7\n",
      "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
      "\n",
      "3加4等于7。\n"
     ]
    }
   ],
   "source": [
    "messages = [HumanMessage(content=\"3加4都等于多少？\")]\n",
    "messages = react_graph.invoke({\"messages\": messages})\n",
    "for m in messages['messages']:\n",
    "    m.pretty_print()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "b517e79c",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "================================\u001b[1m Human Message \u001b[0m=================================\n",
      "\n",
      "把结果再乘以3\n",
      "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
      "\n",
      "请提供要进行乘法运算的第一个结果，我将帮助您将其乘以3。\n"
     ]
    }
   ],
   "source": [
    "messages = [HumanMessage(content=\"把结果再乘以3\")]\n",
    "messages = react_graph.invoke({\"messages\": messages})\n",
    "for m in messages['messages']:\n",
    "    m.pretty_print()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "8ef83aea",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langgraph.checkpoint.memory import MemorySaver\n",
    "memory = MemorySaver()\n",
    "react_graph_memory = builder.compile(checkpointer=memory)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "4ee80330",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "================================\u001b[1m Human Message \u001b[0m=================================\n",
      "\n",
      "3和4相加等于多少\n",
      "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
      "Tool Calls:\n",
      "  add (call_0nIo3VO6dppNNaCPsmkaG3Ls)\n",
      " Call ID: call_0nIo3VO6dppNNaCPsmkaG3Ls\n",
      "  Args:\n",
      "    a: 3\n",
      "    b: 4\n",
      "=================================\u001b[1m Tool Message \u001b[0m=================================\n",
      "Name: add\n",
      "\n",
      "7\n",
      "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
      "\n",
      "3和4相加等于7。\n"
     ]
    }
   ],
   "source": [
    "# 定义一个线程\n",
    "config = {\"configurable\": {\"thread_id\": \"1\"}}\n",
    "\n",
    "# 问题输入\n",
    "messages = [HumanMessage(content=\"3和4相加等于多少\")]\n",
    "\n",
    "messages = react_graph_memory.invoke({\"messages\": messages},config)\n",
    "for m in messages['messages']:\n",
    "    m.pretty_print()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a4b2db48",
   "metadata": {},
   "source": [
    "如果我们传递相同的Thread_id，那么我们可以从之前记录的状态检查点继续！<br/>\n",
    "在这种情况下，上述对话被捕获在线程中。<br/>\n",
    "\n",
    "我们传递的HumanMessage（\"把结果再乘以3\"）被附加到上述对话中。<br/>\n",
    "\n",
    "因此，模型结果that 指的是 3 加 4等于 7。 <br/>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "0f3999b4",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "================================\u001b[1m Human Message \u001b[0m=================================\n",
      "\n",
      "3和4相加等于多少\n",
      "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
      "Tool Calls:\n",
      "  add (call_0nIo3VO6dppNNaCPsmkaG3Ls)\n",
      " Call ID: call_0nIo3VO6dppNNaCPsmkaG3Ls\n",
      "  Args:\n",
      "    a: 3\n",
      "    b: 4\n",
      "=================================\u001b[1m Tool Message \u001b[0m=================================\n",
      "Name: add\n",
      "\n",
      "7\n",
      "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
      "\n",
      "3和4相加等于7。\n",
      "================================\u001b[1m Human Message \u001b[0m=================================\n",
      "\n",
      "把结果再乘以3\n",
      "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
      "Tool Calls:\n",
      "  multiply (call_ITUrZrhYWU9AJxaE1A7CX31r)\n",
      " Call ID: call_ITUrZrhYWU9AJxaE1A7CX31r\n",
      "  Args:\n",
      "    a: 7\n",
      "    b: 3\n",
      "=================================\u001b[1m Tool Message \u001b[0m=================================\n",
      "Name: multiply\n",
      "\n",
      "21\n",
      "==================================\u001b[1m Ai Message \u001b[0m==================================\n",
      "\n",
      "将结果7乘以3等于21。\n"
     ]
    }
   ],
   "source": [
    "messages = [HumanMessage(content=\"把结果再乘以3\")]\n",
    "messages = react_graph_memory.invoke({\"messages\": messages}, config)\n",
    "for m in messages['messages']:\n",
    "    m.pretty_print()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "132916fa",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3.10",
   "language": "python",
   "name": "python310"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.16"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
